`include "defines.v"

module SimTop(
    input         clock,
    input         reset,

    input  [63:0] io_logCtrl_log_begin,
    input  [63:0] io_logCtrl_log_end,
    input  [63:0] io_logCtrl_log_level,
    input         io_perfInfo_clean,
    input         io_perfInfo_dump,

    output        io_uart_out_valid,
    output [7:0]  io_uart_out_ch,
    output        io_uart_in_valid,
    input  [7:0]  io_uart_in_ch
);

// if_stage
wire            flush; 
wire [`I_BUS]   pc;   
wire [`I_BUS]   new_pc;
wire [31: 0]    inst;
wire            inst_ena;
// id_stage
// id_stage -> regfile
wire            rs1_r_ena;
wire [4 : 0]    rs1_r_addr;
wire            rs2_r_ena;
wire [4 : 0]    rs2_r_addr;
wire            rd_w_ena;
wire [4 : 0]    rd_w_addr;
// id_satge -> csr
wire csr_rd_ena;
wire csr_wr_ena;
wire [11:0] csr_addr;
// id_stage -> exe_stage
wire [`REG_BUS] op1;
wire [`REG_BUS] op2;
wire [`REG_BUS] imm;
wire [5:0]      aluop;
// id -> cmt
wire skip_id;


// regfile -> id_stage
wire [`REG_BUS] rs1_data;
wire [`REG_BUS] rs2_data;
// regfile -> difftest
wire [`REG_BUS] regs[0 : 31];

// exe_stage
// exe_stage -> mem_stage
wire [`D_BUS]   mem_addr;
wire [`REG_BUS] rs2;
// exe_stage -> wb_stage
wire            rd_w_ena_o;
wire [4 : 0]    rd_w_addr_o; 
wire [`REG_BUS] rd_data;
wire [5:0]      aluop_o;
//exe_stage -> csr
wire [64:0]     csr_wr_data;
// exe_stage -> cmt
wire halt_ena;
wire skip;

//mem_stage\
//mem -> regfile
wire            	rd_w_ena_mem_o;
wire [4:0]      	rd_w_addr_mem_o;
wire [`REG_BUS] 	rd_w_data_mem_o;
//mem -> ram
wire [`RAM_BUS] 	ram_addr_mem_o;
wire            	ram_wr_ena_mem_o;
wire            	ram_rd_ena_mem_o;
wire [`D_BUS]   	ram_wmask_mem_o;
wire [`D_BUS]   	ram_wr_data_mem_o;

//ram
//ram -> if
wire [63:0] 	  inst_64;
//ram -> mem
wire [63:0] 	ram_rd_data;

// csr_regfile
wire [63:0] 	csr_rd_data;
wire [63:0] 	mstatus_o;
wire [63:0] 	mie_o;
wire [63:0] 	mepc_o;
wire [63:0] 	mcause_o;
wire [63:0] 	mtval_o;
wire [63:0] 	mip_o;
wire [63:0] 	mcycle_o;  
wire [63:0] 	minstret_o;

pc u_pc(
    .clk       ( clock     ),
    .rst       ( reset     ),
    .flush     ( flush     ),
    .new_pc    ( new_pc    ),
	  .inst_64   ( inst_64   ),
    .pc        ( pc        ),
    .inst      ( inst      ),
    .inst_ena  ( inst_ena  )
);

id u_id(
    .rst          ( reset        ),
    .instr_i      ( inst         ),
    .rs1_data_i   ( rs1_data     ),
    .rs2_data_i   ( rs2_data     ),

    .rs1_r_ena_o  ( rs1_r_ena    ),
    .rs1_r_addr_o ( rs1_r_addr   ),
    .rs2_r_ena_o  ( rs2_r_ena    ),
    .rs2_r_addr_o ( rs2_r_addr   ),
    .rd_w_ena_o   ( rd_w_ena     ),
    .rd_w_addr_o  ( rd_w_addr    ),
    .csr_r_ena_o  ( csr_rd_ena   ),
    .csr_w_ena_o  ( csr_wr_ena   ),
    .csr_addr_o   ( csr_addr     ),
    .op1_o        ( op1          ),
    .op2_o        ( op2          ),
    .imm_o        ( imm          ),
    .aluop_o      ( aluop        ),
    .skip_id_o    ( skip_id      )
);

ex u_ex(
    .clock       ( clock       ),
    .rst         ( reset       ),
    .pc_i        ( pc          ),
    .aluop_i     ( aluop       ),
    .op1_i       ( op1         ),
    .op2_i       ( op2         ),
    .imm_i       ( imm         ),
    .rd_w_ena_i  ( rd_w_ena    ),
    .rd_w_addr_i ( rd_w_addr   ),
    .csr_data_i  ( csr_rd_data ),

    .rd_w_ena_o  ( rd_w_ena_o  ),
    .rd_w_addr_o ( rd_w_addr_o ),
    .rd_data_o   ( rd_data     ),
    .csr_data_o  ( csr_wr_data ),
    .aluop_o     ( aluop_o     ),
    .mem_addr_o  ( mem_addr    ),
    .rs2_o       ( rs2         ),
    .new_pc_o    ( new_pc      ),
    .new_branch  ( flush       ),
    .halt_ena    ( halt_ena    ),
    .skip        ( skip        )
);


mem u_mem(
	//ports
	.clk           		( clock         		),
	.rst           		( reset         		),
	.rd_w_ena_i    		( rd_w_ena_o    		),
	.rd_w_addr_i   		( rd_w_addr_o   		),
	.rd_w_data_i   		( rd_data       		),
	.aluop_i       		( aluop_o       		),
	.ram_addr_i    		( mem_addr      		),
	.rs2_i         		( rs2           		),
	.rd_w_ena_o    		( rd_w_ena_mem_o  	),
	.rd_w_addr_o   		( rd_w_addr_mem_o 	),
	.rd_w_data_o   		( rd_w_data_mem_o  	),
	.ram_addr_o    		( ram_addr_mem_o   	),
	.ram_wr_ena_o  		( ram_wr_ena_mem_o 	),
	.ram_rd_ena_o  		( ram_rd_ena_mem_o 	),
	.ram_wmask_o   		( ram_wmask_mem_o  	),
	.ram_wr_data_o 		( ram_wr_data_mem_o	),
	.ram_rd_data_i 		( ram_rd_data 	  	)
);

// 单周期省略wb_stage

regfile u_regfile(
    .clk     ( clock            ),
    .rst     ( reset            ),
    .w_addr  ( rd_w_addr_mem_o  ),
    .w_data  ( rd_w_data_mem_o  ),
    .w_ena   ( rd_w_ena_mem_o   ),

    .r_addr1 ( rs1_r_addr   ),
    .r_data1 ( rs1_data     ),
    .r_ena1  ( rs1_r_ena    ),
    .r_addr2 ( rs2_r_addr   ),
    .r_data2 ( rs2_data     ),
    .r_ena2  ( rs2_r_ena    ),
    .regs_o  (regs          )
);

//I_RAM, D_RAM


RAMHelper u_RAMHelper(
	//ports
	.clk         		( clock       		  ),
	.inst_addr   		( pc   	         	  ),
	.inst_ena    		( inst_ena    	  	),
	.inst_64     		( inst_64     	  	),
	.ram_addr    		( ram_addr_mem_o		),
	.ram_wr_ena  		( ram_wr_ena_mem_o 	),
	.ram_rd_ena  		( ram_rd_ena_mem_o 	),
	.ram_wmask   		( ram_wmask_mem_o  	),
	.ram_wr_data 		( ram_wr_data_mem_o	),
	.ram_rd_data 		( ram_rd_data 	  	)
);


csr_regfile u_csr_regfile(
	//ports
	.clk         		( clock        		),
	.rst         		( reset        		),
	.csr_addr    		( csr_addr    		),
	.csr_rd_ena  		( csr_rd_ena  		),
	.csr_wr_ena  		( csr_wr_ena  		),
	.csr_wr_data 		( csr_wr_data 		),
	.csr_rd_data 		( csr_rd_data 		),
	.mstatus_o   		( mstatus_o   		),
	.mie_o       		( mie_o       		),
	.mepc_o      		( mepc_o      		),
	.mcause_o    		( mcause_o    		),
	.mtval_o     		( mtval_o     		),
	.mip_o       		( mip_o       		),
	.mcycle_o    		( mcycle_o    		),
	.minstret_o  		( minstret_o  		)
);


// Difftest
reg cmt_wen;
reg [7:0] cmt_wdest;
reg [`REG_BUS] cmt_wdata;
reg [`REG_BUS] cmt_pc;
reg [31:0] cmt_inst;
reg cmt_valid;
reg trap;
reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [`REG_BUS] regs_diff [0 : 31];
reg cmt_skip;
//assign regs_diff = regs;

wire inst_valid = (pc != `PC_START) | (inst != 0);

always @(negedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt} <= 0;
  end
  else if (~trap) begin
    cmt_wen <= rd_w_ena;
    cmt_wdest <= {3'd0, rd_w_addr};
    cmt_wdata <= rd_data;
    cmt_pc <= pc;
    cmt_inst <= inst;
    cmt_valid <= inst_valid && ~halt_ena;
    cmt_skip <= skip || skip_id;

		regs_diff <= regs;

    trap <= inst[6:0] == 7'h6b;
    trap_code <= regs[10][7:0];
    cycleCnt <= cycleCnt + 1;
    instrCnt <= instrCnt + inst_valid;
  end
end

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .special            (0),
  .skip               (cmt_skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (regs_diff[0]),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);

DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (`RISCV_PRIV_MODE_M),
  .mstatus            (mstatus_o),
  .sstatus            (0),
  .mepc               (mepc_o),
  .sepc               (0),
  .mtval              (mtval_o),
  .stval              (0),
  .mtvec              (0),
  .stvec              (0),
  .mcause             (mcause_o),
  .scause             (0),
  .satp               (0),
  .mip                (mip_o),
  .mie                (mie_o),
  .mscratch           (0),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);
endmodule